package com.edev.support.ddd.join;

import com.edev.support.dao.BasicDao;
import com.edev.support.ddd.DddException;
import com.edev.support.ddd.utils.EntityBuilder;
import com.edev.support.dsl.Join;
import com.edev.support.entity.Entity;
import com.edev.support.utils.BeanUtils;
import lombok.NonNull;

import java.io.Serializable;
import java.util.*;

/**
 * 实体关联关系抽象基类（模板方法模式）
 * <p>
 * 核心职责：
 * 1. 管理实体间的关联配置（Join）
 * 2. 提供基础DAO操作能力
 * 3. 实现关联数据的统一处理逻辑
 * <p>
 * 泛型参数：
 * @param <E> 实体类型（继承Entity）
 * @param <S> 序列化主键类型
 */
public abstract class AbstractRelation<E extends Entity<S>, S extends Serializable> implements Relation<E,S> {
    protected Join join;
    protected BasicDao dao;

    protected AbstractRelation(@NonNull Join join, @NonNull BasicDao dao) {
        this.join = join;
        this.dao = dao;
    }

    /**
     * 获取关联实体模板（用于构建查询条件）
     * @return 空实体实例（包含类元数据）
     */
    protected Entity<S> getTemplate() {
        return (new EntityBuilder<Entity<S>, S>(join.getClazz())).createEntity();
    }

    /**
     * 获取关联实体类对象（带类型安全检查）
     * @return 实体类的Class对象
     * @throws DddException 当配置的类不是Entity子类时抛出
     */
    @SuppressWarnings("unchecked")
    protected Class<Entity<S>> getClazz() {
        Class<?> clazz = BeanUtils.getClazz(join.getClazz());
        if(!Entity.class.isAssignableFrom(clazz))
            throw new DddException("The class is not an entity: ["+join.getClazz()+"]");
        return (Class<Entity<S>>) clazz;
    }

    /**
     * 根据关联键对实体列表进行分组
     * <p>
     * 分组逻辑：
     * 1. 提取每个实体的关联键值作为分组键
     * 2. 相同键值的实体归入同一列表
     * @param valueList 原始实体集合
     * @return 按关联键分组的实体映射表
     */
    protected Map<S, List<Entity<S>>> sortEntitiesByJoinKey(@NonNull Collection<Entity<S>> valueList) {
        String joinKey = join.getJoinKey();
        Map<S, List<Entity<S>>> sortEntities = new HashMap<>();
        valueList.forEach(entity -> {
            @SuppressWarnings("unchecked")
            S id = (S)entity.getValue(joinKey);
            if(sortEntities.get(id)==null) sortEntities.put(id, new ArrayList<>());
            sortEntities.get(id).add(entity);
        });
        return sortEntities;
    }
}
